import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.ActionUpdateThread;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;


import java.util.Random;
import java.security.SecureRandom;

import java.io.*;
import java.net.*;


import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;

class Constants {
    public static final String APP_NAME = "My Application";
    public static boolean debug_mode  = false;
}
class myConstants {
    public static final String APP_NAME = "My Application";
    public boolean debug_mode  = false;
}

public class CreateLinkageAction extends AnAction {
    
    @Override
    public void actionPerformed(@NotNull AnActionEvent event) {
        // 执行操作时显示对话框
        //Messages.showInfoMessage("Hello from Custom Action!", "Plugin Action");



        // Get all the required data from data keys
        Editor editor = event.getData(CommonDataKeys.EDITOR);
        if (editor == null) return;
        Project project = event.getData(CommonDataKeys.PROJECT);
        if (project == null) return;
        Document document = editor.getDocument();
        //得到文件的总行数
        int cur_linecount = document.getLineCount();









        //Clock.System.out.printf("%d \n" ,  cur_linecount);
        //new NativeConsole.ConsolePrinter().print();
        if (Constants.debug_mode) System.out.println("-----");
        //println("sfsadf");
        if (Constants.debug_mode) System.out.printf("%d \n" ,  cur_linecount);

        qbs04_util util_tool = new  qbs04_util();

        if (editor != null) {
            //得到位置信息, 如果选中了部分文本, 以选中文本尾为准
            int line = editor.getCaretModel().getLogicalPosition().line;
            int column = editor.getCaretModel().getLogicalPosition().column;
            // 处理位置信息
            if (Constants.debug_mode) System.out.printf("   %d  %d \n" ,  line, column);

            // 获取 VirtualFile
            VirtualFile virtualFile = editor.getVirtualFile();
            if (virtualFile != null) {
                String fileName = virtualFile.getName();
                String filePath = virtualFile.getPath();
                String url = virtualFile.getUrl();
                if (Constants.debug_mode) System.out.printf("   %s  %s  %s \n" ,  fileName, filePath, url);

                int 文件类型 = util_tool.get_file_type(fileName);


                String rand_str = util_tool.get_random_string();
                //rand_str = "[" + rand_str + "]";
                String rand_str_with_head_and_tail = util_tool.leading_string[文件类型] + rand_str + util_tool.tail_string[文件类型];
                if (Constants.debug_mode) System.out.printf(" %d  %s  \n" , 文件类型, rand_str);


                String path1 = System.getenv("QBS_INSTALL_PATH_1");
                String path2 = System.getenv("QBS_INSTALL_PATH_2");

                if (Constants.debug_mode) System.out.printf("path1 is [%s]\n", path1);
                if (Constants.debug_mode) System.out.printf("path2 is [%s]\n", path2);

                String relative_path_filename;

                relative_path_filename = PathConverter.getRelativePathUsingPaths(filePath, path1   );
                if (relative_path_filename == null || relative_path_filename.isEmpty()) {
                    if (Constants.debug_mode) System.out.printf("1-relative_path_filename is empty,  this file is not under qbs path1,  try path2 later\n");

                }else{

                    if (Constants.debug_mode) System.out.printf("1-relative_path_filename is [%s]\n", relative_path_filename);
                    if (relative_path_filename.startsWith(".")) {
                        relative_path_filename = null;
                    }else{

                        relative_path_filename = "./" + relative_path_filename;
                    }

                }
                //如果不是path1, 试试path2
                if (relative_path_filename == null || relative_path_filename.isEmpty()) {
                    relative_path_filename = PathConverter.getRelativePathUsingPaths(filePath, path2);
                    if (relative_path_filename == null || relative_path_filename.isEmpty()) {


                            if (Constants.debug_mode) System.out.printf("2-relative_path_filename is empty,  this file is not under qbs path2, will stop later\n");


                    } else {

                        if (Constants.debug_mode) System.out.printf("2-relative_path_filename is [%s]\n", relative_path_filename);
                        if (relative_path_filename.startsWith(".")) {
                            relative_path_filename = null;
                        } else {

                            relative_path_filename = "./" + relative_path_filename;
                        }

                    }
                }

                // path1 path2都试过了, 但是 relative_path_filename is null, stop
                if (relative_path_filename == null || relative_path_filename.isEmpty()) {
                    if (Constants.debug_mode) System.out.printf(" path1 path2都试过了, 但是relative_path_filename is empty,  this file is not under qbs , 就不再继续处理了.\n");
                    String dispaly_str = "path1:" + path1 + "\n"
                                    + "path2:" + path2 + "\n"
                                    + " path1 path2都试过了, 但是relative_path_filename is empty,  this file is not under qbs, 就不再继续处理了.\n(文件必须位于qbs目录之下)";
                    Messages.showInfoMessage(dispaly_str, "QBS04: ");
                    return;

                }

                if (Constants.debug_mode) System.out.printf("relative_path_filename is [%s]\n", relative_path_filename);

                String insert_str = rand_str_with_head_and_tail + " " ; //+ util_tool.start_string_id  + "   " + util_tool.end_string_id;
                // 025-11-01 13:48:29,585 [  12104] SEVERE - #c.i.i.p.PluginManager - Write access is allowed inside write-action only (see Application.runWriteAction());
                // If you access or modify model on EDT consider wrapping your code in WriteIntentReadAction ; see https://jb.gg/ij-platform-threading for details
                //document.insertString(editor.getCaretModel().getCurrentCaret().getSelectionEnd(),  insert_str );
                 WriteCommandAction.runWriteCommandAction(project, () ->
                    /*document.replaceString(start, end, "editor_basics") */
                     document.insertString(editor.getCaretModel().getCurrentCaret().getSelectionEnd(),  insert_str )
                    );

                // 获取 Caret 对象并移动到新的位置
                Caret caret = editor.getCaretModel().getPrimaryCaret();
                caret.moveToOffset(caret.getOffset()+ insert_str.length()); // 移动光标到插入文本的末尾



                String str_to_qbs04 = util_tool.part1 +  rand_str + util_tool.part2 + relative_path_filename + util_tool.part3 + util_tool.part4 + "c or cpp"  + util_tool.part5 + util_tool.part6 ;

                String hostname = "localhost";
                int port = 27193;

                // 使用try-with-resources确保资源自动关闭
                try {
                    Socket socket = new Socket(hostname, port);

                     socket.setSoTimeout(6000);  //6秒超时
                     PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
                     BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()) );

                    if (Constants.debug_mode) System.out.println("已连接到服务器: " + socket.getInetAddress());

                    // 向服务器发送消息
                    out.println(str_to_qbs04);
                    //if (Constants.debug_mode) System.out.println("已向服务器发送问候。");
                    if (Constants.debug_mode) System.out.printf("已向服务器发送:%s\n", str_to_qbs04);


                    // 读取服务器回复
                    //String response = in.readLine();
                    //if (Constants.debug_mode) System.out.println("收到服务器回复: " + response);
                    char[] rec_buffer = new char[4096];
                    int num = in.read(rec_buffer);
                    String rec_str = new String(rec_buffer, 0 , num);
                    //if (Constants.debug_mode) System.out.println will print rec_buffer 的 hash value
                    //if (Constants.debug_mode) System.out.printf("收到服务器回复: %d %d %s\n", num, rec_buffer.length , rec_buffer);
                    //if (Constants.debug_mode) System.out.print(rec_buffer); // will print 4096
                    if (Constants.debug_mode) System.out.printf("收到服务器回复: %d %d %s\n", num, rec_buffer.length , rec_str);
                    String ins_str =   util_tool.start_string_id  + "   " +  rec_str + util_tool.end_string_id;
                    WriteCommandAction.runWriteCommandAction(project, () ->
                    /*document.replaceString(start, end, "editor_basics") */
                     document.insertString(editor.getCaretModel().getCurrentCaret().getSelectionEnd(),  ins_str )
                    );

                } catch (UnknownHostException e) {
                    System.err.println("无法找到服务器主机: " + e.getMessage());
                    Messages.showInfoMessage("无法找到服务器主机, 需要重新启动qbs,或者手动启定服务器.", "QBS04:");
                } catch (IOException e) {
                    System.err.println("与服务器通信时发生I/O错误: " + e.getMessage());
                    Messages.showInfoMessage("服务器超时, 是不是没有选中需要建立连接的 itme ?", "QBS04:");
                }

            }else{
                Messages.showInfoMessage("no filename: this file is not saved. !", "QBS04:");

            }
        }
        // remove it , it is ok, only reference
         if (false) {
             // 方法1：通过 PsiFile 获取
             PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());

             if (psiFile != null) {
                 String fileName = psiFile.getName();
                 Messages.showInfoMessage("当前文件名: " + fileName, "文件信息");
             }
         }








        if (false) {


            // Work off of the primary caret to get the selection info
            Caret primaryCaret = editor.getCaretModel().getPrimaryCaret();
            int start = primaryCaret.getSelectionStart();
            int end = primaryCaret.getSelectionEnd();

            // Replace the selection with a fixed string.
            // Must do this document change in a write action context.
            WriteCommandAction.runWriteCommandAction(project, () ->
                    document.replaceString(start, end, "editor_basics")
            );

            // De-select the text range that was just replaced
            primaryCaret.removeSelection();
        }
    }
    
    @Override
    public void update(@NotNull AnActionEvent e) {
        // 根据上下文启用或禁用Action
        // 例如：只有在有项目打开时才启用
        boolean hasProject = e.getProject() != null;
        e.getPresentation().setEnabled(hasProject);
    }
    
    @Override
    public @NotNull ActionUpdateThread getActionUpdateThread() {
        // 在事件调度线程上执行update方法
        return ActionUpdateThread.EDT;
    }
}

class qbs04_util{
    boolean debug_mode;

    String home_dir_1;
    String home_dir_2;
    int file_type;
    int  rand_string_length;



    String start_string_id = "(%%";
    String end_string_id   = "%%)";

    String part1 =  """
<cmd-end/>
<cmd-start/>

<set-target-canvas>
<canvas-filename>CURRENT-CANVAS</canvas-filename>
</set-target-canvas>
<网络文件独占模式>
 <action--drop-package 
		       parent-uid = "FIRST-CHOOSED" 
                       x="500" y ="400"  
		       XY-确定方法 = "FIRST-CHOOSED > RIGHT-TOP > 0 > 0"
                       flags = "x-y-is-canvas-coordinate"
                       filename="./package/000/pkg/src-location.better.pkg" start-pos="48" 
                       />
<sequence-operation-on-package>
     <package-uid>CREATED-JUST-NOW</package-uid> 

<port-index> 4  </port-index>   <port-value> """;


    String part2 = "</port-value> <port-index> 5  </port-index>   <port-value>";
    String part3 = "</port-value>";
    String part4 = """
<package-uid>FIRST-CHOOSED</package-uid>
<get-package-or-jci-include-self/>
<发送canvas定位xml命令>
      <文件类型>""";

    String part5 = "</文件类型>";
    String part6 = """
</发送canvas定位xml命令>
</sequence-operation-on-package >
</网络文件独占模式>
<cmd-end/>   """;


    public String getHome_dir_1() {
        return home_dir_1;
    }

    public void setHome_dir_1(String home_dir_1) {
        this.home_dir_1 = home_dir_1;
    }


      public String getHome_dir_2() {
        return home_dir_2;
    }

    public void setHome_dir_2(String home_dir_2) {
        this.home_dir_2 = home_dir_2;
    }


    public int getFile_type() {
        return file_type;
    }

    public void setFile_type(int file_type) {
        this.file_type = file_type;
    }

    public int getRand_string_length() {
        return rand_string_length;
    }

    public void setRand_string_length(int rand_string_length) {
        this.rand_string_length = rand_string_length;
    }


    enum file_type{
        FILE_TYPE__UNKNOWN(0),
        FILE_TYPE__C_SERIES(1),
        FILE_TYPE__SHELL(2),
        FILE_TYPE__ELISP(3),
        FILE_TYPE__PYTHON(4),
        FILE_TYPE__JAVA(5);
        private final int value;
        file_type(int i) {
            this.value = i;
        }
        public int toInt() {
            return this.value;
        }
    }

     //file_type ft = new file_type(0);
    int FILE_TYPE__UNKNOWN = 0;
    int FILE_TYPE__C_SERIES = 1;
    int FILE_TYPE__SHELL = 2;
    int FILE_TYPE__ELISP = 3;
    int FILE_TYPE__PYTHON  = 4;
    int FILE_TYPE__JAVA = 5;
    String[] leading_string = {"[", "//[" , "#[" , ";["  ,"#[" , "//["};
    String[] tail_string = {"]", "]" , "]" , "]"  ,"]" , "]"};

    int get_file_type(String fileName){
        if (fileName == null || fileName.isEmpty()) {
            return FILE_TYPE__UNKNOWN;
        }
        int lastDotIndex = fileName.lastIndexOf(".");
        if (lastDotIndex == -1) {
            return FILE_TYPE__UNKNOWN;
        }
        String suffix = fileName.substring(lastDotIndex + 1);
        //return Arrays.stream(suffixWhiteList).anyMatch(x -> x.equalsIgnoreCase(suffix));
        if (suffix == null || suffix.isEmpty()) {
            //return FILE_TYPE__UNKNOWN;
        }else {
            if ((suffix.equalsIgnoreCase("c")) ||
                (suffix.equalsIgnoreCase("h")) ||
                (suffix.equalsIgnoreCase("cpp")) ||
                (suffix.equalsIgnoreCase("hpp"))

               ){
                return  FILE_TYPE__C_SERIES;

            }else if (suffix.equalsIgnoreCase("sh")) {
                return  FILE_TYPE__SHELL;
            } else if ( suffix.equalsIgnoreCase("el")) {
                return  FILE_TYPE__ELISP;
            }else if ( suffix.equalsIgnoreCase("py")) {
                return  FILE_TYPE__PYTHON;
            }else if ((suffix.equalsIgnoreCase("java")) ||
                (suffix.equalsIgnoreCase("kt")) ||
                (suffix.equalsIgnoreCase("kts")) ||
                (suffix.equalsIgnoreCase("ktm"))

               ) {
                return FILE_TYPE__JAVA;

            }
        }
        return FILE_TYPE__UNKNOWN;
    }



        // 无参构造函数
    public qbs04_util() {
        // 初始化代码
        debug_mode = false;
        this.rand_string_length = 20;
        this.home_dir_1 = "";
        this.home_dir_2 = "";


    }

    // 有参构造函数
    public qbs04_util(String name, int age) {
        // 使用参数初始化字段
        debug_mode = false;
        this.rand_string_length = age;
        this.home_dir_1 = "";
        this.home_dir_2 = "";

    }

   public String get_random_string(){
        return generateMixedCase(this.rand_string_length);
    }



    public String get_random_string_with_length(int length){
        return generateMixedCase(length);



    }

        /**
     * 生成包含数字和小写字母的随机字符串
     */
    public static String generateLowerCase(int length) {
        StringBuilder builder = new StringBuilder(length);
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            int type = random.nextInt(2);
            if (type == 0) {
                // 生成小写字母
                builder.append((char)(random.nextInt(26) + 'a'));
            } else {
                // 生成数字
                builder.append((char)(random.nextInt(10) + '0'));
            }
        }
        return builder.toString();
    }

    /**
     * 生成包含数字、大小写字母的随机字符串
     */
    public static String generateMixedCase(int length) {
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        StringBuilder builder = new StringBuilder(length);
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            builder.append(chars.charAt(random.nextInt(chars.length())));
        }
        return builder.toString();
    }

    /**
     * 使用SecureRandom生成安全随机字符串
     */
    public static String generateSecureMixed(int length) {
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        StringBuilder builder = new StringBuilder(length);
        SecureRandom random = new SecureRandom();
        for (int i = 0; i < length; i++) {
            builder.append(chars.charAt(random.nextInt(chars.length())));
        }
        return builder.toString();
    }

    public static void main(String[] args) {
        // 测试示例
        if (Constants.debug_mode) System.out.println("小写字母和数字: " + generateLowerCase(10));
        if (Constants.debug_mode) System.out.println("混合字符: " + generateMixedCase(12));
        if (Constants.debug_mode) System.out.println("安全随机字符串: " + generateSecureMixed(8));
    }

}


class TCPClient {
    private Socket socket;

    public void connect(String host, int port) throws IOException {
        socket = new Socket(host, port);
        if (Constants.debug_mode) System.out.println("连接到服务器: " + host + ":" + port);
    }

    public void sendMessage(String message) throws IOException {
        OutputStream output = socket.getOutputStream();
        PrintWriter writer = new PrintWriter(output, true);
        writer.println(message);
    }

    public String receiveMessage() throws IOException {
        InputStream input = socket.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(input));
        return reader.readLine();
    }

    public void disconnect() throws IOException {
        if (socket != null && !socket.isClosed()) {
            socket.close();
            if (Constants.debug_mode) System.out.println("连接已断开");
        }
    }
}

class PathConverter {
    public static void main(String[] args) {
        // 示例文件路径
        String fullPath = "C:\\Users\\username\\Documents\\example.txt";
        String baseDir = "C:\\Users\\username";

        if (Constants.debug_mode) System.out.println("完整路径: " + fullPath);
        if (Constants.debug_mode) System.out.println("基准目录: " + baseDir);
        if (Constants.debug_mode) System.out.println("=== 方法一: 使用File类 ===");
        String relativePath1 = getRelativePathUsingFile(fullPath, baseDir);
        if (Constants.debug_mode) System.out.println("相对路径: " + relativePath1);

        if (Constants.debug_mode) System.out.println("=== 方法二: 使用Paths类 ===");
        String relativePath2 = getRelativePathUsingPaths(fullPath, baseDir);
        if (Constants.debug_mode) System.out.println("相对路径: " + relativePath2);

        // 使用当前工作目录作为基准的示例
        if (Constants.debug_mode) System.out.println("=== 相对于当前工作目录 ===");
        String currentRelative = getRelativeToCurrentDir(fullPath);
        if (Constants.debug_mode) System.out.println("相对路径: " + currentRelative);
    }

    /**
     * 使用File类获取相对路径
     */
    public static String getRelativePathUsingFile(String fullPath, String basePath) {
        File file = new File(fullPath);
        String absolutePath = file.getAbsolutePath();

        // 确保基准路径以分隔符结尾
        if (!basePath.endsWith(File.separator)) {
            basePath += File.separator;
        }

        String relativePath = absolutePath.replace(basePath, "");
        return relativePath.isEmpty() ? "." : relativePath;
    }

    /**
     * 使用Paths类获取相对路径（推荐）
     */
    public static String getRelativePathUsingPaths(String fullPath, String basePath) {
        try {
            Path filePath = Paths.get(fullPath);
            Path baseDirPath = Paths.get(basePath);
            Path relativePath = baseDirPath.relativize(filePath);
            return relativePath.toString();
        } catch (IllegalArgumentException e) {
            System.err.println("错误: 路径不兼容 - " + e.getMessage());
            return fullPath;
        }
    }

    /**
     * 获取相对于当前工作目录的路径
     */
    public static String getRelativeToCurrentDir(String fullPath) {
        String workingDir = System.getProperty("user.dir");
        return getRelativePathUsingPaths(fullPath, workingDir);
    }
}